package regEx.finiteAutomata;


public class NFA {

    private State startState;

    private State endState;

    private int numStates;

    /** Adjacency Matrix representing the NFA */
    private char[][] adjacencyMatrix;

    public NFA() {
    };

    public NFA(State startState, State endState) {
        this.startState = startState;
        this.endState = endState;
    };

    public State getStartState() {
        return startState;
    }

    public void setStartState(State startState) {
        this.startState = startState;
    }

    public State getEndState() {
        return endState;
    }

    public void setEndState(State endState) {
        this.endState = endState;
    }

    public int getNumStates() {
        return numStates;
    }

    public void setNumStates(int numStates) {
        this.numStates = numStates;
    }
    /**
     * Print this NFA as an adjacency Matrix
     * @return
     */
    public String toString() {
        // If the nfaAdjacencyMatrix is initialized, then print it out as a string
        if (adjacencyMatrix != null) {
            StringBuffer nfaAsString = new StringBuffer();

            // Build top row of states
            nfaAsString.append("   ");
            for (int c = 0; c < adjacencyMatrix[0].length; c++) {
                nfaAsString.append(c + " ");
            }
            for (int i = 0; i < adjacencyMatrix[0].length; i++) {
                nfaAsString.append("\n" + i + (i < 10 ? "  " : " "));
                for (int j = 0; j < adjacencyMatrix[0].length; j++) {
                    nfaAsString.append(adjacencyMatrix[i][j] + (j > 9 ? "  " : " "));
                }
            }
            return nfaAsString.toString();
        }

        // Create a new Adjacency Matrix
        adjacencyMatrix = new char[this.getNumStates()][this.getNumStates()];

        // Clear out the cells
        for (int i = 0; i < this.getNumStates(); i++) {
            for (int j = 0; j < this.getNumStates(); j++) {
                this.adjacencyMatrix[i][j] = ' ';
            }
        }

        // Construct the Adjacency Matrix
        constructAdjacencyMatrix(this.getStartState());

        // since the nfaAdjacencyMatrix is initialized now
        return toString();
    }

    /**
     * For each node in the FA, starting with the startState, recursively add the states with their
     * transitions to the nfaAdjacencyMatrix.
     * @param state
     */
    private void constructAdjacencyMatrix(State state) {
        for (Transition transition : state.getTransitionsArray()) {
            if (!transition.isVisited()) {
                transition.setVisited(true);
                this.adjacencyMatrix[state.getId()][transition.getToState().getId()] = transition.getTransitionValue();
                constructAdjacencyMatrix(transition.getToState());
            }
        }
    }

}
